using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BSDS.Core.Model.Data;

namespace BSDS.Core.Data.Local.Xml.Seralization
{
    public class XmlFormatSerializer : ISerializer
    {
        public void Serialize(EntityValue[] entities, string entityTypeName, string filename)
        {
            Serialize(entities, entityTypeName, filename, SerializationOptions.None);
        }

        public void Serialize(EntityValue[] entities, string entityTypeName, string filename, SerializationOptions options)
        {

            using (var xmlWriter = new StreamWriter(new FileStream(filename, FileMode.Create)))
            {
                xmlWriter.Write(XmlFormatTemplates.Header);

                GenerateXmlSchema(entities[0].AttributeInfos, entityTypeName, xmlWriter);
                GenerateXmlData(entities, entityTypeName, xmlWriter, options);

                xmlWriter.Write(XmlFormatTemplates.Trailer);
            }
        }

        private static void GenerateXmlData(IEnumerable<EntityValue> entities, string entityTypeName, StreamWriter xmlWriter,
            SerializationOptions options)
        {
            var xmlEntitiesBuilder = new StringBuilder();

            foreach (EntityValue entity in entities)
            {
                var xmlEntityBuilder = new StringBuilder();

                foreach (AttributeValue attributeValue in entity.AttributeValues)
                {
                    xmlEntityBuilder.Append(ToXmlElement(attributeValue, options));
                }

                xmlEntitiesBuilder.Append(String.Format(XmlFormatTemplates.Entity, entityTypeName, xmlEntityBuilder));
            }

            xmlWriter.Write(xmlEntitiesBuilder);
        }

        private static void GenerateXmlSchema(IEnumerable<AttributeInfo> attributeInfos, string entityTypeName, StreamWriter xmlWriter)
        {
            string elementsSection = GenerateXmlSchemaElementsSection(attributeInfos);
            string primaryKeyName = attributeInfos.First(a => a.IsPrimaryKey).Name;

            xmlWriter.Write(String.Format(XmlFormatTemplates.Schema, entityTypeName, elementsSection, primaryKeyName));
        }

        private static string GenerateXmlSchemaElementsSection(IEnumerable<AttributeInfo> attributeInfos)
        {
            var attributesXmlSchemaBuilder = new StringBuilder();

            attributeInfos.ToList().ForEach(a => attributesXmlSchemaBuilder.AppendLine(ToXmlSchemaElement(a)));

            return attributesXmlSchemaBuilder.ToString();
        }

        private static string ToXmlSchemaElement(AttributeInfo attributeInfo)
        {
            var datatype = attributeInfo.Datatype.ToLower();

            if (datatype == "datetime")
            {
                datatype = "dateTime";
            }

            return String.Format(XmlFormatTemplates.SchemaElement, attributeInfo.Name, datatype);
        }

        private static string ToXmlElement(AttributeValue attributeValue, SerializationOptions options)
        {
            var utils = new SerializationUtils();

            var value = utils.EscapeSpecialCharacters(utils.GetValue(attributeValue, options));
            if(attributeValue.AttributeInfo.Datatype.ToLower() == "boolean")
            {
                value = value.ToLower();
            }

            return String.Format(XmlFormatTemplates.EntityAttribute, attributeValue.AttributeInfo.Name, value);
        }
    }
}